package com.dhj.jvmstudy.chapter08;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * 虚引用的测试
 */
public class PhantomReferenceTest {

    // 当前类对象的声明
    public static PhantomReferenceTest obj;

    static ReferenceQueue<PhantomReferenceTest> phantomQueue = null; // 虚应用队列

    public static class CheckRefQueue extends Thread {
        @Override
        public void run() {
            while (true){
                if(phantomQueue != null){
                    PhantomReference<PhantomReferenceTest> objt = null;
                    try {
                        objt = (PhantomReference<PhantomReferenceTest>) phantomQueue.remove();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    if(objt != null){
                        System.out.println("追踪垃圾回收过程，PhantomReferenceTest实例被GC了");
                    }
                }
            }

        }
    }

    // finalized()方法只能被调用1次
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("调用当前类的finalize()方法");
        obj = this;
    }

    public static void main(String[] args) {
        Thread t = new CheckRefQueue();
        t.setDaemon(true); // 设置为守护线程：当程序中没有非守护线程时，守护线程也就执行结束。
        t.start();

        phantomQueue = new ReferenceQueue<PhantomReferenceTest>();
        obj = new PhantomReferenceTest();
        // 构造了PhantomReferenceTest对象的虚引用，并指向了队列引用
        PhantomReference<PhantomReferenceTest> phantomRef = new PhantomReference<>(obj, phantomQueue);

        try {
            // 不可获取虚引用中的对象
            System.out.println(phantomRef.get());
            // 将强引用去除
            obj = null;

            // 第一次进行GC，由于对象可复活，GC无法回收该对象
            System.gc();
            Thread.sleep(1000);

            if(obj == null){
                System.out.println("obj 是 null");
            }else{
                System.out.println("obj 可用");
            }
            System.out.println("第2次gc");
            obj = null;
            System.gc(); // 一旦将obj对象回收，就会将此虚引用存放到引用队列中。
            Thread.sleep(1000);
            if(obj == null){
                System.out.println("obj 是 null");
            }else{
                System.out.println("obj 可用");
            }

        }catch (Exception e){
            e.printStackTrace();
        }

    }

}